﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace Red.EngineData.Helpers
{
    public class InteropDebugInfo
    {
        #region Properties

        /// <summary>
        /// Information about caller file path
        /// </summary>
        public string CallerFilePath
        {
            get
            {
                if ( StackFrames == null || StackFrames.Length == 0 )
                    return "Unknown file";

                return StackFrames[0].GetFileName();
            }
        }

        /// <summary>
        /// Information about caller line number
        /// </summary>
        public int CallerLineNumber
        {
            get
            {
                if ( StackFrames == null || StackFrames.Length == 0 )
                    return -1;

                return StackFrames[0].GetFileLineNumber();
            }
        }

        /// <summary>
        /// Information about caller member name
        /// </summary>
        public string CallerMemberName
        {
            get
            {
                if ( StackFrames == null || StackFrames.Length == 0 )
                    return "Unknown method";

                return StackFrames[0].GetMethod().Name;
            }
        }

        /// <summary>
        /// Time point for calculate time between interop request and answer
        /// </summary>
        public double CreationTime;

        /// <summary>
        /// Stack trace related to our code
        /// </summary>
        public StackFrame[] StackFrames;

        /// <summary>
        /// Expression sent to interop engine service
        /// </summary>
        public string InteropExpression;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor
        /// </summary>
        /// <param name="stackFrames">Full stack frace</param>
        public InteropDebugInfo( string expression, StackFrame[] stackFrames )
        {
            InteropExpression = expression;

            if ( stackFrames != null )
                ExtractOnlyOurCode( stackFrames );

            CreationTime = DateTime.Now.TimeOfDay.TotalSeconds;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Extract stack trace with our codes from full stack trace 
        /// </summary>
        /// <param name="stackFrames">Full stack trace</param>
        private void ExtractOnlyOurCode( StackFrame[] stackFrames )
        {
            List<StackFrame> frames = new List<StackFrame>();

            foreach ( var frame in stackFrames.Reverse() )
            {
                if ( string.IsNullOrEmpty( frame.GetFileName() ) )
                {
                    continue;
                }

                frames.Add( frame );

                if ( frame.GetMethod().Name == "Execute" || frame.GetMethod().Name == "ExecuteAsync" )
                {
                    frames.RemoveAt( frames.Count - 1 );
                    break;
                }
            }

            frames.Reverse();
            StackFrames = frames.ToArray();
        }

        #endregion
    }
}
